import sys
from PyQt6.QtWidgets import QApplication,QMainWindow
from PyQt6.QtCore import pyqtSignal,QUrl,pyqtSlot
from sls_mqttClient import MQTTClient
from main_window_ui import Ui_MainWindow
from PyQt6.QtWebEngineWidgets import QWebEngineView
from PyQt6.QtWebChannel import QWebChannel
import io
import folium
import json
import math
from PyQt6.QtCore import QObject
import time
import os

# 判断坐标是否在中国范围内
def out_of_china(lng, lat):
    return not (72.004 <= lng <= 137.8347 and 0.8293 <= lat <= 55.8271)

# 转换算法辅助函数
def transformlat(x, y):
    ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * math.sqrt(abs(x))
    ret += (20.0 * math.sin(6.0 * x * math.pi) + 20.0 * math.sin(2.0 * x * math.pi)) * 2.0 / 3.0
    ret += (20.0 * math.sin(y * math.pi) + 40.0 * math.sin(y / 3.0 * math.pi)) * 2.0 / 3.0
    ret += (160.0 * math.sin(y / 12.0 * math.pi) + 320 * math.sin(y * math.pi / 30.0)) * 2.0 / 3.0
    return ret

# 转换算法辅助函数
def transformlng(x, y):
    ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * math.sqrt(abs(x))
    ret += (20.0 * math.sin(6.0 * x * math.pi) + 20.0 * math.sin(2.0 * x * math.pi)) * 2.0 / 3.0
    ret += (20.0 * math.sin(x * math.pi) + 40.0 * math.sin(x / 3.0 * math.pi)) * 2.0 / 3.0
    ret += (150.0 * math.sin(x / 12.0 * math.pi) + 300.0 * math.sin(x / 30.0 * math.pi)) * 2.0 / 3.0
    return ret

# WGS - 84 转 GCJ - 02
def wgs84_to_gcj02(lng, lat):
    if out_of_china(lng, lat):
        return [lng, lat]
    dlat = transformlat(lng - 105.0, lat - 35.0)
    dlng = transformlng(lng - 105.0, lat - 35.0)
    radlat = lat / 180.0 * math.pi
    magic = math.sin(radlat)
    magic = 1 - 0.00669342162296594323 * magic * magic
    sqrtmagic = math.sqrt(magic)
    dlat = (dlat * 180.0) / ((6378245.0 * (1 - 0.00669342162296594323)) / (magic * sqrtmagic) * math.pi)
    dlng = (dlng * 180.0) / (6378245.0 / sqrtmagic * math.cos(radlat) * math.pi)
    mglat = lat + dlat
    mglng = lng + dlng
    return [mglng, mglat]

# GCJ - 02 转 WGS - 84
def gcj02_to_wgs84(lng, lat):
    if out_of_china(lng, lat):
        return [lng, lat]
    dlat = transformlat(lng - 105.0, lat - 35.0)
    dlng = transformlng(lng - 105.0, lat - 35.0)
    radlat = lat / 180.0 * math.pi
    magic = math.sin(radlat)
    magic = 1 - 0.00669342162296594323 * magic * magic
    sqrtmagic = math.sqrt(magic)
    dlat = (dlat * 180.0) / ((6378245.0 * (1 - 0.00669342162296594323)) / (magic * sqrtmagic) * math.pi)
    dlng = (dlng * 180.0) / (6378245.0 / sqrtmagic * math.cos(radlat) * math.pi)
    mglat = lat + dlat
    mglng = lng + dlng
    return [lng - (mglng - lng), lat - (mglat - lat)]

 # 镇江的江苏大学的经纬度119.515293, 32.199403
default_latitude = 32.199403
defualt_longitude = 119.515293

mglong,mglat = gcj02_to_wgs84(defualt_longitude,default_latitude)
class MapInteraction(QObject):
    def __init__(self, main_window):
        super().__init__()  # 调用父类 QObject 的构造函数
        self.main_window = main_window

    @pyqtSlot(float, float)
    def showCoordinates(self, latitude, longitude):
        self.main_window.statusBar_signal.emit(f"点击位置坐标：{latitude}, {longitude}")
   
    @pyqtSlot()
    def mapLoaded(self):
        self.main_window.mapLoaded = True
        self.main_window.statusBar_signal.emit("地图加载完成")

class GCMainWindow(QMainWindow):
    statusBar_signal = pyqtSignal(str)
    mapUpdate_signal = pyqtSignal(str)

    def __init__(self):
        super().__init__()

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.mqtt_client = MQTTClient()
        self.mqtt_client.set_connect_handle_callback(self.mqtt_connect_handle_callback)
        self.mqtt_client.set_message_handle_callback(self.mqtt_message_handle_callback)

        self.statusBar_signal.connect(self.ui.statusbar.showMessage)
        self.ui.statusbar.showMessage("mqtt连接中...")

        # 创建 QWebEngineView 并添加到布局中
        self.web_view = QWebEngineView()
        self.ui.verticalLayout.addWidget(self.web_view)
        self.mapUpdate_signal.connect(self.map_update)

        # 创建 QWebChannel 对象
        self.channel = QWebChannel()
        self.web_view.page().setWebChannel(self.channel)

        # 创建并注册只包含必要方法的对象
        self.map_interaction = MapInteraction(self)
        self.channel.registerObject('pyObj', self.map_interaction)

        # 初始化无人机箭头标记的 JavaScript 变量
        self.fly1_arrow_marker_js = None
        self.fly1_js_code = None
        self.fly2_arrow_marker_js = None
        self.fly2_js_code = None
        self.mapLoaded = False

        self.generate_map()

        self.mqtt_client.connect()

    def map_update(self, js_code):
        self.web_view.page().runJavaScript(js_code)

    def mqtt_message_handle_callback(self, client, userdata, msg):
        if  self.mapLoaded != True:
            return
        topic = msg.topic
        message = msg.payload.decode()
     #   self.statusBar_signal.emit(f"收到消息：{topic} {message}")
        js_code = ''
        if topic == "/status/fly1/PR":
            messageDict = json.loads(message)
            gnss_position = messageDict["GNSS_position"]
            latitude = gnss_position["latitude"]
            longitude = gnss_position["longitude"]
            vehicle_yaw:float = messageDict["vehicle_yaw"]
            #转换为gcj02坐标显示在高德地图上
            longitude,latitude = wgs84_to_gcj02(longitude,latitude)
            #建立fly1的javescript变量和函数
            if self.fly1_arrow_marker_js is None:
                # 如果箭头标记还未创建，则创建它

                self.fly1_arrow_marker_js = 'window.fly1_arrowMarker'
            else:
                js_code += f"fly1_marker.setLatLng([{latitude}, {longitude}]);"
            # self.mapUpdate_signal.emit(self.fly1_js_code)

        if topic == "/status/fly2/PR":
            messageDict = json.loads(message)
            gnss_position = messageDict["GNSS_position"]
            latitude = gnss_position["latitude"]
            longitude = gnss_position["longitude"]
            vehicle_yaw:float = messageDict["vehicle_yaw"]
            longitude,latitude = wgs84_to_gcj02(longitude,latitude)
            if self.fly2_arrow_marker_js is None:
                # 如果箭头标记还未创建，则创建它
                js_code += f"""
                var fly2_arrowIcon = L.divIcon({{
                    className: 'arrow-icon',
                    html: '<div style="width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-bottom: 10px solid purple; transform: rotate({vehicle_yaw * (180 / math.pi)}deg);"></div>',
                    iconSize: [80, 80]
                }});
                var fly2_arrowMarker = L.marker([{latitude}, {longitude}], {{icon: fly2_arrowIcon}}).addTo(globalMap);
                window.fly2_arrowMarker = fly2_arrowMarker;
                """
                self.fly2_arrow_marker_js = 'window.fly2_arrowMarker'
            else:
                js_code += f"{self.fly2_arrow_marker_js}.setLatLng([{latitude}, {longitude}]);"    
            #self.mapUpdate_signal.emit(self.fly2_js_code)
        if js_code != '':
            self.mapUpdate_signal.emit(js_code)

    def mqtt_connect_handle_callback(self, client, userdata, flags, rc):
        self.statusBar_signal.emit("mqtt连接成功")
        self.mqtt_client.subscribe_topics(["/status/fly1/PR"])
        self.mqtt_client.subscribe_topics(["/status/fly2/PR"])

    def generate_map(self):
        # 创建 folium 地图对象（修正初始缩放级别为18）
        m = folium.Map(location=[default_latitude, defualt_longitude],zoom_start=18, control_scale=True, max_zoom=22)

        # 修改高德普通地图瓦片配置（添加 tile_url_function）
        gaode_normal_tiles = folium.TileLayer(
            tiles='http://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
            attr='高德地图',
            subdomains='1234',
            max_zoom=18,
            name='高德普通地图'
        )

        # 修改高德卫星地形图瓦片配置（添加 tile_url_function）
        gaode_satellite_tiles = folium.TileLayer(
            tiles='http://wprd04.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=6',
            attr='高德地图',
            subdomains='1234',
            max_zoom=18,
            name='高德卫星地形图'
        )
        Esri_WorldImagery = folium.TileLayer(
           tiles= 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
           attr='Esri',
           name='Esri_WorldImagery',
           max_zoom=22,
           overlay=False,
        )
        Esri_WorldImagery.add_to(m)
        
        gaode_normal_tiles.add_to(m)

        # 添加高德卫星地形图瓦片
        gaode_satellite_tiles.add_to(m)

        # 添加标记到地图上，并添加自定义属性
        marker = folium.Marker([default_latitude, defualt_longitude], icon=folium.Icon(color='blue'))
        marker2 = folium.Marker([mglat, mglong], icon=folium.Icon(color='red'))

        #import os
        #获取当前脚本所在目录
        # script_dir = os.path.dirname(os.path.abspath(__file__))
        # js_file_path = os.path.join(script_dir, 'leaflet.rotatedMarker.js')
        # rotated_marker_js = f'<script src="{js_file_path}"></script>'

        # # Add Leaflet library CSS and JavaScript files
        # leaflet_css = '<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin=""/>'
        # leaflet_js = '<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>'

        # m.get_root().header.add_child(folium.Element(leaflet_css))
        # m.get_root().header.add_child(folium.Element(leaflet_js))
        # m.get_root().header.add_child(folium.Element(rotated_marker_js))

        # script_dir = os.path.dirname(os.path.abspath(__file__))
        # js_file_path = os.path.join(script_dir, 'leaflet.rotatedMarker.js')
        # rotated_marker_js = f'<script src="{js_file_path}"></script>'
        # m.get_root().header.add_child(folium.Element(rotated_marker_js))
        # 给标记添加自定义属性
        marker.add_to(m)
        marker2.add_to(m)
        marker._id = 'location_marker'

        # 添加图层控制
        folium.LayerControl().add_to(m)

        # 保存地图为 HTML 文件
        data = io.BytesIO()
        m.save(data, close_file=False)
        html_content = data.getvalue().decode()

        # 注入 QWebChannel.js 和必要的样式
        html_content = html_content.replace('</head>',
            """
        <script src="qrc:///qtwebchannel/qwebchannel.js"></script> <!-- 注入 qwebchannel.js -->
        // 全局变量，用于保存 Leaflet 地图对象
        var globalMap;
        var fly1_marker;


        // 监听 DOM 加载完成事件
        document.addEventListener('DOMContentLoaded', function() {
            // 每隔 100 毫秒检查 Leaflet 地图是否加载完成
            var checkLeaflet = setInterval(function() {
                // 过滤出所有 Leaflet 地图对象
                var maps = Object.values(window).filter(function(value) {
                    return value && value._initHooksCalled && value.getContainer;
                });

                // 如果找到地图对象，则清除定时器
                if (maps.length > 0) {
                    clearInterval(checkLeaflet);
                    globalMap = maps[0];
                    // 创建初始标记

                    marker = L.marker([32.190903,119.516293], { icon: L.icon({ iconUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png', iconSize: [25, 41], iconAnchor: [12, 41] }) }).addTo(globalMap);

                    // 等待 QWebChannel 初始化完成
                    new QWebChannel(qt.webChannelTransport, function(channel) {
                        var pyObj = channel.objects.pyObj;
                        pyObj.mapLoaded();
                        
                        var fly1_marker = L.marker([32.190903,119.516293],{rotationAngle: 45}).addTo(globalMap);
                        // 添加地图点击事件监听
                        globalMap.on('click', function(e) {
                            var lat = e.latlng.lat;
                            var lng = e.latlng.lng;
                            pyObj.showCoordinates(lat, lng);
                        });
                    });

                    
                }
            }, 100);
        });
        </script>
        </head>

        """)
        # 设置 baseUrl 以确保可以加载 qwebchannel.js
        self.web_view.setHtml(html_content, baseUrl=QUrl("qrc:/"))  # 指定 baseUrl






if __name__ == "__main__":
    app = QApplication(sys.argv)
    main_window = GCMainWindow()
    main_window.show()
    sys.exit(app.exec())
